package com.liholin.springboot.sample.filter;

import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.liholin.springboot.sample.config.AppConfigProperties;
import com.liholin.springboot.sample.configdata.ResponseData;
import com.liholin.springboot.sample.exception.ErrorStatus;
import com.liholin.springboot.sample.service.AccessTokenService;
import com.liholin.springboot.sample.service.RedisService;
import com.liholin.springboot.sample.utils.JWTUtil;
import com.liholin.springboot.sample.utils.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Administrator
 * @version 1.0
 * @date 2020/2/2
 * @since Jdk 1.8
 */
@Slf4j
public class HttpControllerAuthorizeFilter extends OncePerRequestFilter {

    private PathMatcher pathMatcher = new AntPathMatcher();
    private AppConfigProperties properties;
    private ObjectMapper objectMapper;
    private AccessTokenService accessTokenService;
    private RedisService redisService;


    public HttpControllerAuthorizeFilter(AppConfigProperties properties, AccessTokenService tokenService, ObjectMapper objectMapper, RedisService redisService) {
        this.properties = properties;
        this.objectMapper = objectMapper;
        this.accessTokenService = tokenService;
        this.redisService = redisService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
        try {
            String uri = request.getRequestURI();
            String method = request.getMethod();

            if ("OPTIONS".equalsIgnoreCase(method)) {
                filterChain.doFilter(request, response);
                return;
            }

            String paramApp = request.getParameter("app");
            if (!StringUtils.equals(paramApp, this.properties.getNewShopApp())) {
                responseErrorHandler(response, ResponseData.Companion.error("app参数不正确",ErrorStatus.ERROR_400011));
               return;
            }

            String path = request.getRequestURI();
            if (matchesIgnoredPatterns(path)) {
                log.info("ignored url," + path);
                filterChain.doFilter(request, response);
                return;
            }

            log.info("web auth url," + path);

            /**/
            //权限验证过程

            String token = ServletUtil.getToken(request, "");
            String uid = "";
            String userId = "";
            HashMap<String, String> map = new HashMap<>();

            if (token == null || "".equals(token)) {
                map.put("msg", "token无效!!");
            } else if (paramApp == null || paramApp.trim().equals("")) {
                map.put("msg", "token无效!!");
            } else {
                try {
                    JWTUtil.verify(token);//验证令牌
                    String payload = JWTUtil.getTokenInfo(token).getPayload();
                    final Base64.Decoder decoder = Base64.getDecoder();
                    JsonObject userInfoJson = new Gson().fromJson(new String(decoder.decode(payload), "UTF-8"), JsonObject.class);
                    String un = userInfoJson.get("un").getAsString();
                    String app = userInfoJson.get("app").getAsString();
                    String userIdByRedis = userInfoJson.get("userId").getAsString();

                    if (app.equals(paramApp)) {
                        Map<String, Object> userInfoMap = null;
                        userInfoMap = redisService.HGetByKey(un);
                        if (userInfoMap == null || userInfoMap.size() == 0) {
                            map.put("msg", "token无效!!");
                            log.info("token无效!!");
                        } else {
                            String redisToken = userInfoMap.get(app).toString();
                            if (redisToken.equals(token)) {
                                log.info("放行请求");
                                uid = un;
                                userId = userIdByRedis;
                            } else {
                                map.put("msg", "token无效!!");
                                log.info("token无效!!");
                            }
                        }
                    } else {
                        map.put("msg", "token无效!!");
                    }
                } catch (SignatureVerificationException e) {
                    e.printStackTrace();
                    map.put("msg", "无效签名!");
                } catch (TokenExpiredException e) {
                    e.printStackTrace();
                    map.put("msg", "token过期!");
                } catch (AlgorithmMismatchException e) {
                    e.printStackTrace();
                    map.put("msg", "token算法不一致!");
                } catch (Exception e) {
                    e.printStackTrace();
                    map.put("msg", "token无效!!");
                }
            }

            if (!map.isEmpty()) {
                responseErrorHandler(response, ResponseData.Companion.error(ErrorStatus.USER_UNAUTHORIZED));
            }

            RequestHeaderWrapper requestHeaderWrapper = new RequestHeaderWrapper(request);

            requestHeaderWrapper.putHeader("uid", uid);
            requestHeaderWrapper.putHeader("userId", userId);
            filterChain.doFilter(requestHeaderWrapper, response);

            return;

        } catch (Exception e) {
            log.error("HttpFilter Error:" + e.getMessage(), e);
            responseErrorHandler(response, ResponseData.Companion.error(ErrorStatus.USER_UNAUTHORIZED));
            return;
        }
    }


    protected boolean matchesIgnoredPatterns(String path) {
        if (this.properties.getIgnoredUrls() == null) {
            return false;
        }

        for (String pattern : this.properties.getIgnoredUrls()) {
            log.debug("Matching ignored pattern:" + pattern);
            if (this.pathMatcher.match(pattern, path)) {
                log.debug("Path " + path + " matches ignored pattern " + pattern);
                return true;
            }
        }
        return false;
    }

    private void responseErrorHandler(HttpServletResponse response, ResponseData errorResult) {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET,DELETE,PUT,OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization,x-ailife-authorization,x-yscloud-saas-clientId,x-yscloud-saas-eid,x-yscloud-saas-uid");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.setStatus(HttpStatus.OK.value());
        try {
            response.getWriter().write(objectMapper.writeValueAsString(errorResult));
            response.getWriter().flush();
            response.getWriter().close();
        } catch (IOException e) {
            log.error("HttpFilter response error:" + e.getMessage(), e);
        }

    }
}